﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BasePlatformNet
{
	public class PacketBuilder
	{
		// UDP 协议标记： true = 采用 UDP 协议发送数据; false = 采用自定协议发送数据
		private bool useUDP = true;

		// 使用 winpcap 发包标记：组包时带有 MAC 帧头、IP 帧头、UDP 帧头
		private bool useWinPcap = true;

		// 底层使用交换机标记
		private bool useSwitch = false;

		// 初始化 MAC 帧头, 不包括前导字段和帧起始界定符, 9~22字节, 共 14bytes
		private byte[] macHeader_UDP = Tools.StringToHexByte("FFFFFFFFFFFF0000000000000800");

		// 发包时使用的源 MAC 地址
		private string macSrc = "FFFFFFFFFFFF";

		// 初始化 MAC 帧头, 目的 MAC 为广播地址, 用于帧包和显示设置包, 不包括前导字段和帧起始界定符, 9~22字节, 共 14bytes
		private byte[] macHeader_UDP_switchBreadcast = null;
		private List<byte[]> macHeader_UDP_switchPort = null;

		// 初始化 IP 帧头, 版本=ipv4, 生存时间=1, 源ip地址/目的ip地址无用, IP数据段长度66（0x42）, 23~42字节, 共 20bytes
		private byte[] ipHeader_UDP = Tools.StringToHexByte("450000425F69000001110000AC100150E0010101");
		
		// 初始化 UDP 帧头, UDP数据段长度46（0x2E）, 43~50字节, 共 8bytes
		private byte[] udpHeader_UDP = Tools.StringToHexByte("55A955AA002E8EA2");

		// 借用 macHeader 变量, 实际为广播目的地址
		private byte[] macHeader_noUDP = Tools.StringToHexByte("FFFFFFFFFFFF");
		
		// 借用 ipHeader 变量, 实际为广播源地址
		private byte[] ipHeader_noUDP = Tools.StringToHexByte("000000000000");
		
		// 借用 ipHeader 变量, 实际为目的端口55AA
		private byte[] udpHeader_noUDP = Tools.StringToHexByte("55AA");

		// MAC、IP、UDP 帧头
		private byte[] macHeader = null;		// MAC 帧头
		private byte[] ipHeader = null;			// IP 帧头
		private byte[] udpHeader = null;		// UDP 帧头
		
		// 自定义协议头
		private byte[] infoField = Tools.StringToHexByte("81F50100000000");

        // 空 UDP 帧头 - 放置于socket发送队列第二个包开始
        private byte[] idleHeader_UDP = Tools.StringToHexByte("000055AA00000000");
		// 行映射表、分控映射表、附属设备映射表
		public  List<byte[]> macBytesList = null;
		public  int[] rowMacIndex = null;
		public  int[] rowOffset = null;
		private int[] subMacIndex = null;
		private int[] subOffset = null;
		private int[] equMacIndex = null;
		private int[] equOffset = null;

		// 构造函数
		public PacketBuilder(string macAddr)
		{
			macSrc = "FFFFFFFFFFFF";
			
			if (macAddr != null && !macAddr.Trim().Equals(""))
			{
				// 设置源 MAC 为当前网卡的 MAC 地址
				macSrc = macAddr.Trim().Replace("-", "").Replace(":", "");
			}
			else
			{
				// 设置源 MAC 为当前广播 MAC 地址
				macSrc = "FFFFFFFFFFFF";
			}

			macHeader_UDP_switchBreadcast = Tools.StringToHexByte("FFFFFFFFFFFF" + macSrc + "0800");	// 目的 MAC 为广播地址
		}

		// 设置是否支持交换机
		public void setUseSwitch(bool useSwitch)
		{
			this.useSwitch = useSwitch;
		}

		// 设置是否使用 winpcap 发包
		public void setUseWinPcap(bool useWinPcap)
		{
			this.useWinPcap = useWinPcap;
		}

		// 【支持交换机】构造映射表, 将 List 数组化, 提高效率
		public void makeMacTables(List<string> macList, List<MacTable> rowMacTable, List<MacTable> subMacTable, List<MacTable> equMacTable)
		{
			int macLength = Tools.StringToHexByte("FFFFFFFFFFFF").Length;
			macBytesList = new List<byte[]>();
			macHeader_UDP_switchPort = new List<byte[]>();
			for(int i = 0; i < macList.Count; i++)
			{
				macBytesList.Add(Tools.StringToHexByte(macList[i]));
				macHeader_UDP_switchPort.Add(Tools.StringToHexByte(macList[i] + macSrc + "0800"));
			}

			rowMacIndex = new int[BaseCoreNet.maxSubEquNum * 8];
			rowOffset = new int[BaseCoreNet.maxSubEquNum * 8];
			subMacIndex = new int[BaseCoreNet.maxSubEquNum];
			subOffset = new int[BaseCoreNet.maxSubEquNum];
			equMacIndex = new int[BaseCoreNet.maxSubEquNum];
			equOffset = new int[BaseCoreNet.maxSubEquNum];

			/********************************************************************/
			
			for (int i = 0; i < rowMacTable.Count; i++)
			{
				rowMacIndex[i] = int.Parse(rowMacTable[i].macIndex);
				rowOffset[i] = rowMacTable[i].offset;
			}
			string lastMac = rowMacTable[rowMacTable.Count - 1].macIndex;
			int lastOffset = rowMacTable[rowMacTable.Count - 1].offset;
			for (int i = rowMacTable.Count; i < BaseCoreNet.maxSubEquNum * 8; i++)
			{
				rowMacIndex[i] = int.Parse(lastMac);
				rowOffset[i] = lastOffset;
			}

			/********************************************************************/

			for (int i = 0; i < subMacTable.Count; i++)
			{
				subMacIndex[i] = int.Parse(subMacTable[i].macIndex);
				subOffset[i] = subMacTable[i].offset;
			}
			lastMac = subMacTable[subMacTable.Count - 1].macIndex;
			lastOffset = subMacTable[subMacTable.Count - 1].offset;
			for (int i = subMacTable.Count; i < BaseCoreNet.maxSubEquNum; i++)
			{
				subMacIndex[i] = int.Parse(lastMac);
				subOffset[i] = lastOffset;
			}

			/********************************************************************/

			for (int i = 0; i < equMacTable.Count; i++)
			{
				equMacIndex[i] = int.Parse(equMacTable[i].macIndex);
				equOffset[i] = equMacTable[i].offset;
			}
			lastMac = equMacTable[equMacTable.Count - 1].macIndex;
			lastOffset = equMacTable[equMacTable.Count - 1].offset;
			for (int i = equMacTable.Count; i < BaseCoreNet.maxSubEquNum; i++)
			{
				equMacIndex[i] = int.Parse(lastMac);
				equOffset[i] = lastOffset;
			}

			/********************************************************************/
		}

		// 初始化帧头 MAC + IP + UDP
		private void initHeaders()
		{
			if (useUDP == true)
			{
				if (useSwitch == true)
				{
					macHeader = macHeader_UDP_switchBreadcast;
					ipHeader = ipHeader_UDP;
					udpHeader = udpHeader_UDP;
				}
				else
				{
					macHeader = macHeader_UDP;
					ipHeader = ipHeader_UDP;
					udpHeader = udpHeader_UDP;
				}
			}
			else
			{
				macHeader = macHeader_noUDP;
				ipHeader = ipHeader_noUDP;
				udpHeader = udpHeader_noUDP;
			}
		}

		// 初始化帧头 MAC + IP + UDP - 支持交换机, 目的 MAC 根据分控号查表
		private byte[] initHeaders(string target, int targetDepth)
		{
			byte[] macHeader_tmp = null;
			if (useUDP == true)
			{
				if (macHeader_UDP_switchPort == null || macHeader_UDP_switchPort.Count == 0)
				{
					macHeader_tmp = macHeader_UDP_switchBreadcast;
				}
				else if (targetDepth == 0)
				{
					macHeader_tmp = macHeader_UDP_switchBreadcast;
				}
				else
				{
					if (target.Equals(InnerCommandTarget.SubCtrl))
					{
						macHeader_tmp = macHeader_UDP_switchPort[subMacIndex[targetDepth - 1]];
					}
					else if (target.Equals(InnerCommandTarget.Equipment))
					{
						macHeader_tmp = macHeader_UDP_switchPort[equMacIndex[targetDepth - 1]];
					}
				}

				ipHeader = ipHeader_UDP;
				udpHeader = udpHeader_UDP;
			}
			else
			{
				macHeader_tmp = macHeader_noUDP;
				
				ipHeader = ipHeader_noUDP;
				udpHeader = udpHeader_noUDP;
			}

			return macHeader_tmp;
		}

		// 初始化帧头 MAC + IP + UDP - 支持交换机, 目的 MAC 根据交换机端口索引查表
		private byte[] initHeaders4SwitchDisp(int switchPortIndex)
		{
			byte[] macHeader_tmp = null;
			
			if (useUDP == true)
			{
				if (macHeader_UDP_switchPort == null || macBytesList.Count == 0 || switchPortIndex < 0)
				{
					macHeader_tmp = macHeader_UDP_switchBreadcast;
				}
				else
				{
					macHeader_tmp = macHeader_UDP_switchPort[switchPortIndex];
				}

				ipHeader = ipHeader_UDP;
				udpHeader = udpHeader_UDP;
			}
			else
			{
				macHeader_tmp = macHeader_noUDP;
				ipHeader = ipHeader_noUDP;
				udpHeader = udpHeader_noUDP;
			}

			return macHeader_tmp;
		}

		// 创建帧包
		// para1: channelNumPerRow	- 显示图像实际宽度 - 每行的通道数
		// para2: height_pixel		- 显示图像实际高度 - 像素数
		public byte[] buildFramePacket(int channelNumPerRow, int height_pixel)
		{
			initHeaders();

			int totalHeaderLength = macHeader.Length + ipHeader.Length + udpHeader.Length;

			byte[] infoField = Tools.StringToHexByte("81FA0100000000");		// 51 ~ 57 字节, 7bytes

			byte[] showAddress = Tools.StringToHexByte("00000000");			// 58 ~ 61 字节：目标地址 - 保留, 4bytes

			byte[] dataLength = Tools.int2Byte2(25);						// 62 ~ 63 字节：有效数据长度 m=25, 2bytes

			byte[] view_width = Tools.int2Byte2(channelNumPerRow);				// 64 ~ 65 字节

			byte[] view_height = Tools.int2Byte2(height_pixel);				// 66 ~ 67 字节

			byte[] packetDataSize = Tools.int2Byte2(LEDPacket.SHOW_DATA_LENGTH);					// 68 ~ 69 字节

			byte[] load = Tools.StringToHexByte("00000000000000000000000000000000000000");	// 长度已修正

			int totalLength = 0;
			if (useWinPcap)
			{
				totalLength = totalHeaderLength + infoField.Length + showAddress.Length + dataLength.Length	+ view_width.Length + view_height.Length + packetDataSize.Length + load.Length;
			}
			else
			{
				totalLength = infoField.Length + showAddress.Length + dataLength.Length + view_width.Length + view_height.Length + packetDataSize.Length + load.Length;
			}
			
			byte[] allFrameBytes = new byte[totalLength];

			int index = 0;
			if (useWinPcap)
			{
				Tools.addByte(ref allFrameBytes, macHeader, ref index);
				Tools.addByte(ref allFrameBytes, ipHeader, ref index);
				Tools.addByte(ref allFrameBytes, udpHeader, ref index);
			}
			Tools.addByte(ref allFrameBytes, infoField, ref index);
			Tools.addByte(ref allFrameBytes, showAddress, ref index);
			Tools.addByte(ref allFrameBytes, dataLength, ref index);
			Tools.addByte(ref allFrameBytes, view_width, ref index);
			Tools.addByte(ref allFrameBytes, view_height, ref index);
			Tools.addByte(ref allFrameBytes, packetDataSize, ref index);
			Tools.addByte(ref allFrameBytes, load, ref index);

			// winpcap发包：设置【帧包】校验和 0xCBDF
			if (useWinPcap)
			{
				if (useUDP)
				{
					allFrameBytes[0x18] = 0xCB;
					allFrameBytes[0x19] = 0xDF;
				}
			}

			return allFrameBytes;
		}

		// 创建帧包【根据参数对象】
		// para1: 帧包参数对象
		// 源MAC: 本端口MAC, 目的MAC: 广播地址
		public byte[] buildFramePacket(FramePacketPara packetPara)
		{
			initHeaders();

			int totalHeaderLength = macHeader.Length + ipHeader.Length + udpHeader.Length;

			byte[] infoField = Tools.StringToHexByte("81FA0100000000");		// 51 ~ 57 字节, 7bytes

			byte[] showAddress = Tools.StringToHexByte("00000000");			// 58 ~ 61 字节：目标地址 - 保留, 4bytes

			byte[] dataLength = Tools.int2Byte2(25);						// 62 ~ 63 字节：有效数据长度 m=25, 2bytes

			byte[] view_width = Tools.int2Byte2(packetPara.row_bytes);		// 64 ~ 65 字节

			byte[] view_height = Tools.int2Byte2(packetPara.row_num);		// 66 ~ 67 字节

			byte[] packetDataSize = Tools.int2Byte2(packetPara.packetDataSize);	// 68 ~ 69 字节

			byte[] load = Tools.StringToHexByte("00000000000000000000000000000000000000");	// 长度已修正

			int totalLength = 0;
			if (useWinPcap)
			{
				totalLength = totalHeaderLength + infoField.Length + showAddress.Length + dataLength.Length + view_width.Length + view_height.Length + packetDataSize.Length + load.Length;
			}
			else
			{
				totalLength = infoField.Length + showAddress.Length + dataLength.Length + view_width.Length + view_height.Length + packetDataSize.Length + load.Length;
			}

			byte[] allFrameBytes = new byte[totalLength];

			int index = 0;
			if (useWinPcap)
			{
				Tools.addByte(ref allFrameBytes, macHeader, ref index);
				Tools.addByte(ref allFrameBytes, ipHeader, ref index);
				Tools.addByte(ref allFrameBytes, udpHeader, ref index);
			}
			Tools.addByte(ref allFrameBytes, infoField, ref index);
			Tools.addByte(ref allFrameBytes, showAddress, ref index);
			Tools.addByte(ref allFrameBytes, dataLength, ref index);
			Tools.addByte(ref allFrameBytes, view_width, ref index);
			Tools.addByte(ref allFrameBytes, view_height, ref index);
			Tools.addByte(ref allFrameBytes, packetDataSize, ref index);
			Tools.addByte(ref allFrameBytes, load, ref index);

			// winpcap发包：设置【帧包】校验和 0xCBDF
			if (useWinPcap)
			{
				if (useUDP)
				{
					allFrameBytes[0x18] = 0xCB;
					allFrameBytes[0x19] = 0xDF;
				}
			}

			return allFrameBytes;
		}

		// 创建显示设置包
		// para1: overall		- 全局操作标记
		// para2: blackScreen	- 黑屏标记
		public byte[] buildDispConfigPacket(bool overall, bool blackScreen)
		{
			initHeaders();

			byte[] ipHeader_fix;
			byte[] udpHeader_fix;
			if (useUDP == true)
			{
				// Fix：修正 IP 帧头 - 设置有效数据长度 = 553 = 0x0229
				ipHeader_fix = Tools.StringToHexByte("450002295F69000001110000AC100150E0010101");

				// Fix：修正 UDP 帧头 - 设置有效数据长度 = 533 = 0x0215
				udpHeader_fix = Tools.StringToHexByte("55A955AA02158EA2");
			}
			else
			{
				ipHeader_fix = ipHeader;
				udpHeader_fix = udpHeader;
			}

			int totalHeaderLength = macHeader.Length + ipHeader_fix.Length + udpHeader_fix.Length;

			byte[] infoField = Tools.StringToHexByte("81F00100000000");		// 51 ~ 57字节

			byte[] confAddress;												// 58 ~ 61字节：设置地址 - 保留

			if (overall)
			{
				confAddress = Tools.StringToHexByte("FF000000");	// 全局操作
			}
			else
			{
				confAddress = Tools.StringToHexByte("00000000");	// 非全局操作
			}

			byte[] dataLength = Tools.int2Byte2(512);				// 62 ~ 63字节：有效数据长度 m=512

			byte[] load = new byte[512];

			// 填充显示设置包负载数据
			byte[] fillData16 = new byte[16];
			if (blackScreen)
			{
				fillData16 = Tools.StringToHexByte("08000040FFFFFFFF0000000000000000");
			}
			else
			{
				fillData16 = Tools.StringToHexByte("00000040FFFFFFFF0000000000000000");
			}
			for (int k = 0; k < 512 / 16; k++)
			{
				Array.Copy(fillData16, 0, load, k * 16, 16);
			}

			int totalLength = 0;
			if (useWinPcap)
			{
				totalLength = totalHeaderLength + infoField.Length + confAddress.Length + dataLength.Length + load.Length;
			}
			else
			{
				totalLength = infoField.Length + confAddress.Length + dataLength.Length + load.Length;
			}

			byte[] allFrameBytes = new byte[totalLength];

			int index = 0;
			if (useWinPcap)
			{
				Tools.addByte(ref allFrameBytes, macHeader, ref index);
				Tools.addByte(ref allFrameBytes, ipHeader_fix, ref index);
				Tools.addByte(ref allFrameBytes, udpHeader_fix, ref index);
			}
			Tools.addByte(ref allFrameBytes, infoField, ref index);
			Tools.addByte(ref allFrameBytes, confAddress, ref index);
			Tools.addByte(ref allFrameBytes, dataLength, ref index);
			Tools.addByte(ref allFrameBytes, load, ref index);

			// winpcap发包：设置【显示设置包】校验和 0xC9F8
			if (useWinPcap)
			{
				if (useUDP)
				{
					allFrameBytes[0x18] = 0xC9;
					allFrameBytes[0x19] = 0xF8;
				}
			}

			return allFrameBytes;
		}

		// 创建显示设置包【根据参数对象】
		// para1: 显示设置包参数对象
		// 源MAC: 本端口MAC, 目的MAC: 广播地址
		public byte[] buildDispConfigPacket(DispConfigPacketPara packetPara)
		{
			initHeaders();

			byte[] ipHeader_fix;
			byte[] udpHeader_fix;
			if (useUDP == true)
			{
				// Fix：修正 IP 帧头 - 设置有效数据长度 = 553 = 0x0229
				ipHeader_fix = Tools.StringToHexByte("450002295F69000001110000AC100150E0010101");

				// Fix：修正 UDP 帧头 - 设置有效数据长度 = 533 = 0x0215
				udpHeader_fix = Tools.StringToHexByte("55A955AA02158EA2");
			}
			else
			{
				ipHeader_fix = ipHeader;
				udpHeader_fix = udpHeader;
			}

			int totalHeaderLength = macHeader.Length + ipHeader_fix.Length + udpHeader_fix.Length;

			byte[] infoField = Tools.StringToHexByte("81F00100000000");		// 51 ~ 57字节

			byte[] confAddress;												// 58 ~ 61字节：设置地址 - 保留

			if (packetPara.overall)
			{
				confAddress = Tools.StringToHexByte("FF000000");	// 全局操作
			}
			else
			{
				confAddress = Tools.StringToHexByte("00000000");	// 非全局操作
			}

			byte[] dataLength = Tools.int2Byte2(512);				// 62 ~ 63字节：有效数据长度 m=512

			byte[] load = new byte[512];

			// 填充显示设置包负载数据
			byte[] configData_16 = packetPara.buildConfigData();
			for (int k = 0; k < 512 / 16; k++)
			{
				Array.Copy(configData_16, 0, load, k * 16, 16);
			}

			int totalLength = 0;
			if (useWinPcap)
			{
				totalLength = totalHeaderLength + infoField.Length + confAddress.Length + dataLength.Length + load.Length;
			}
			else
			{
				totalLength = infoField.Length + confAddress.Length + dataLength.Length + load.Length;
			}

			byte[] allFrameBytes = new byte[totalLength];

			int index = 0;
			if (useWinPcap)
			{
				Tools.addByte(ref allFrameBytes, macHeader, ref index);
				Tools.addByte(ref allFrameBytes, ipHeader_fix, ref index);
				Tools.addByte(ref allFrameBytes, udpHeader_fix, ref index);
			}
			Tools.addByte(ref allFrameBytes, infoField, ref index);
			Tools.addByte(ref allFrameBytes, confAddress, ref index);
			Tools.addByte(ref allFrameBytes, dataLength, ref index);
			Tools.addByte(ref allFrameBytes, load, ref index);

			// winpcap发包：设置【显示设置包】校验和 0xC9F8
			if (useWinPcap)
			{
				if (useUDP)
				{
					allFrameBytes[0x18] = 0xC9;
					allFrameBytes[0x19] = 0xF8;
				}
			}

			return allFrameBytes;
		}

		// 创建显示数据包
		// para1: loadData		- 显示数据, 固定1459字节, 480pixel;
		// para2: address_row	- 显示地址, 计算得到：行地址、列地址
		// para3: address_line	- 显示长度, 图像实际宽度（像素数） * 3
		public byte[] buildShowDataPacket(byte[] loadData, byte[] address_row, byte[] address_line, int showLength, int switchPortIndex)
		{
			byte[] macHeader4SwitchDisp = null;
			
			// 支持交换机
			if (useSwitch == true && switchPortIndex >= 0)
			{
				macHeader4SwitchDisp = initHeaders4SwitchDisp(switchPortIndex);		// 根据行号查表, 确定行包的目的 MAC 地址
			}
			// 不支持交换机
			else
			{
				initHeaders();
			}

			int totalHeaderLength = 0;
			if (useSwitch == true && macHeader4SwitchDisp != null)
			{
				totalHeaderLength = macHeader4SwitchDisp.Length + ipHeader.Length + udpHeader.Length;
			}
			else
			{
				totalHeaderLength = macHeader.Length + ipHeader.Length + udpHeader.Length;
			}

			byte[] showAddress_row = address_row;

			byte[] showAddress_line = address_line;

			byte[] dataLength = Tools.int2Byte2(showLength);

			byte[] load = loadData;

			int totalLength = 0;
			if (useWinPcap)
			{
				totalLength = totalHeaderLength + infoField.Length + showAddress_row.Length + showAddress_line.Length + dataLength.Length + load.Length;
			}
			else
			{
				totalLength = infoField.Length + showAddress_row.Length + showAddress_line.Length + dataLength.Length + load.Length;
			}

			byte[] allFrameBytes = new byte[totalLength];

			int index = 0;
			if (useWinPcap)
			{
				if (useSwitch == true && macHeader4SwitchDisp != null)
				{
					Tools.addByte(ref allFrameBytes, macHeader4SwitchDisp, ref index);
				}
				else
				{
					Tools.addByte(ref allFrameBytes, macHeader, ref index);
				}
				Tools.addByte(ref allFrameBytes, ipHeader, ref index);
				Tools.addByte(ref allFrameBytes, udpHeader, ref index);
			}
			Tools.addByte(ref allFrameBytes, infoField, ref index);
			Tools.addByte(ref allFrameBytes, showAddress_row, ref index);
			Tools.addByte(ref allFrameBytes, showAddress_line, ref index);
			Tools.addByte(ref allFrameBytes, dataLength, ref index);
			Tools.addByte(ref allFrameBytes, load, ref index);

			// winpcap发包：修正 UDP 报文长度、IP 报文长度
			if (useWinPcap)
			{
				int udpLength = infoField.Length + showAddress_row.Length + showAddress_line.Length + dataLength.Length + load.Length + 8;
				byte[] udpLengthBytes = Tools.int2Byte2(udpLength);
				byte[] ipLengthBytes = Tools.int2Byte2(udpLength + 20);
				allFrameBytes[0x26] = udpLengthBytes[1];
				allFrameBytes[0x27] = udpLengthBytes[0];
				allFrameBytes[0x10] = ipLengthBytes[1];
				allFrameBytes[0x11] = ipLengthBytes[0];
			}

			// winpcap发包：设置【显示数据包】校验和 0xC658
			if (useWinPcap)
			{
				if (useUDP)
				{
					allFrameBytes[0x18] = 0xC6;
					allFrameBytes[0x19] = 0x58;
				}
			}

			return allFrameBytes;
		}

		// 创建通信命令包：专用于 "定点读命令"
		// para1: target			- 操作目标
		// para1: targetDepth		- 分控/附属设备的级联深度
		// para2: packageId			- 随机包标识符
		// para3: addr2Read			- 数据读取地址
		public byte[] buildCommandPacket4Read(string target, int targetDepth, int packageId, int addr2Read)
		{
			byte[] macHeader4Switch = null;
			
			// 支持交换机
			if (useSwitch == true)
			{
				macHeader4Switch = initHeaders(target, targetDepth);	// 根据分控级联深度查表, 设置目的 MAC

				// 根据分控级联深度查表, 修正级联深度（减偏移量）
				if (target.Equals(InnerCommandTarget.SubCtrl))
				{
					if (subOffset != null && subOffset.Length > 0)
					{
						targetDepth -= subOffset[targetDepth - 1];
					}
				}
				// 根据附属设备级联深度查表, 修正级联深度（减偏移量）
				else if (target.Equals(InnerCommandTarget.Equipment))
				{
					if (equOffset != null && equOffset.Length > 0)
					{
						targetDepth -= equOffset[targetDepth - 1];
					}
				}
			}
			// 不支持交换机
			else
			{
				initHeaders();
			}

			// 协议版本号 + 包标识符 + 当前附属设备级联深度（主控为0） + 当前分控级联深度（主控为0）
			byte[] infoField = Tools.StringToHexByte("81C50100000000");		// 51 ~ 57 字节

			/************************** 目标地址 58 ~ 61 字节 ****************************/

			// 地址类型
			byte addrType = 0x0;		// "定点操作" 分控及附属设备, bit0=0, bit1=0, bit7~bit2 为 0 

			// 校验目标分控深度
			if (target.Equals(InnerCommandTarget.SubCtrl))
			{
				if (targetDepth < 0 || targetDepth > 255)
				{
					throw new Exception("Wrong targetSubCtrlDepth value: " + targetDepth);
				}
			}
			else if (target.Equals(InnerCommandTarget.Equipment))
			{
				if (targetDepth < 0 || targetDepth > 63)
				{
					throw new Exception("Wrong targetEquipmentDepth value: " + targetDepth);
				}
			}

			byte addr1 = 0x0;	// 地址字节1 - 目标分控级联深度
			if (target.Equals(InnerCommandTarget.SubCtrl))
			{
				addr1 = (byte)(0xff & targetDepth);
			}
			else
			{
				addr1 = 0x0;	// 为 0, 表示不操作任何分控
			}

			byte addr2 = 0x0;	// 地址字节2 - 分控定点分线器号 - 暂为 0

			byte addr3 = 0x0;	// 地址字节3 - 目标附属设备级联深度
			if (target.Equals(InnerCommandTarget.Equipment))
			{
				addr3 = (byte)(0xff & targetDepth);
			}
			else
			{
				addr3 = 0x0;	// 为 0, 表示不操作任何附属设备
			}

			byte[] targetAddr = new byte[4];
			targetAddr[0] = addrType;
			targetAddr[1] = addr1;
			targetAddr[2] = addr2;
			targetAddr[3] = addr3;

			/***************************** END 目标地址 ********************************/

			byte[] effectDataLenth = Tools.int2Byte2(264);	// 有效数据长度 2+1+1+1+1+1+1+256=264

			/**************************** 命令数据 264字节 ******************************/

			byte[] pkgId = Tools.int2Byte2(packageId);

			// 命令类型
			byte commandCode = 0x08;		// 读 Memory：0x08

			// 保留字节
			byte resveredInCmdData = 0x00;

			// 命令地址 - 4字节
			byte[] addrInCmdData = Tools.int2Byte4(addr2Read);

			// 命令数据 - 256字节0x00
			byte[] dataInCmdData = new byte[256];
			for (int k = 0; k < 256; k++)
			{
				dataInCmdData[k] = 0x0;
			}

			/***************************** END 命令数据 *******************************/

			byte[] ipHeader_fix;
			byte[] udpHeader_fix;
			if (useUDP == true)
			{
				// Fix：修正 IP 帧头 - 设置有效数据长度 = 305 = 0x0131
				ipHeader_fix = Tools.StringToHexByte("450001315F69000001110000AC100150E0010101");

				// Fix：修正 UDP 帧头 - 设置有效数据长度 = 285 = 0x011D
				udpHeader_fix = Tools.StringToHexByte("55A955AA011D8EA2");
			}
			else
			{
				ipHeader_fix = ipHeader;
				udpHeader_fix = udpHeader;
			}

			// 包头长度：MAC帧头 + IP帧头 + UDP帧头
			int totalHeaderLength = 0;
			if (useSwitch == true && macHeader4Switch != null)
			{
				totalHeaderLength = macHeader4Switch.Length + ipHeader_fix.Length + udpHeader_fix.Length;
			}
			else
			{
				totalHeaderLength = macHeader.Length + ipHeader_fix.Length + udpHeader_fix.Length;
			}

			// 组装完整的通信命令包
			int totalLength = 0;
			if (useWinPcap)
			{
				totalLength = totalHeaderLength + infoField.Length + targetAddr.Length + effectDataLenth.Length + pkgId.Length + 1 + 1 + addrInCmdData.Length + dataInCmdData.Length;
			}
			else
			{
				totalLength = infoField.Length + targetAddr.Length + effectDataLenth.Length + pkgId.Length + 1 + 1 + addrInCmdData.Length + dataInCmdData.Length;
			}

			byte[] allFrameBytes = new byte[totalLength];

			int index = 0;
			if (useWinPcap)
			{
				if (useSwitch == true && macHeader4Switch != null)
				{
					Tools.addByte(ref allFrameBytes, macHeader4Switch, ref index);
				}
				else
				{
					Tools.addByte(ref allFrameBytes, macHeader, ref index);
				}
				Tools.addByte(ref allFrameBytes, ipHeader_fix, ref index);
				Tools.addByte(ref allFrameBytes, udpHeader_fix, ref index);
			}
			Tools.addByte(ref allFrameBytes, infoField, ref index);
			Tools.addByte(ref allFrameBytes, targetAddr, ref index);
			Tools.addByte(ref allFrameBytes, effectDataLenth, ref index);
			Tools.addByte(ref allFrameBytes, pkgId, ref index);
			Tools.addByte(ref allFrameBytes, commandCode, ref index);
			Tools.addByte(ref allFrameBytes, resveredInCmdData, ref index);
			Tools.addByte(ref allFrameBytes, addrInCmdData, ref index);
			Tools.addByte(ref allFrameBytes, dataInCmdData, ref index);

			// winpcap发包：设置【通信命令包】校验和 CAF0
			if (useWinPcap)
			{
				if (useUDP)
				{
					allFrameBytes[0x18] = 0xCA;
					allFrameBytes[0x19] = 0xF0;
				}
			}

			return allFrameBytes;
		}

		// 创建通信命令包：专用于 "定点写命令/全局写命令"
		// para1: target			- 操作目标
		// para2: subControlDepth	- 分控/附属设备的级联深度
		// para3: packageId			- 随机包标识符
		// para4: addr4Write		- 数据写入地址
		// para5: loadData			- 要写入的数据
		// para6: forAllFlag		- 全局操作标识
		public byte[] buildCommandPacket4Write(string target, int targetDepth, int packageId, int addr2Write, byte[] loadData, bool overallFlag)
		{
			byte[] macHeader4Switch = null;

			// 支持交换机
			if (useSwitch == true)
			{
				if (overallFlag == true)
				{
					macHeader4Switch = macHeader_UDP_switchBreadcast;
				}
				else
				{
					macHeader4Switch = initHeaders(target, targetDepth);	// 根据分控级联深度查表, 设置目的 MAC

					// 根据分控级联深度查表, 修正级联深度（减偏移量）
					if (target.Equals(InnerCommandTarget.SubCtrl))
					{
						if (subOffset != null && subOffset.Length > 0)
						{
							targetDepth -= subOffset[targetDepth - 1];
						}
					}
					// 根据附属设备级联深度查表, 修正级联深度（减偏移量）
					else if (target.Equals(InnerCommandTarget.Equipment))
					{
						if (equOffset != null && equOffset.Length > 0)
						{
							targetDepth -= equOffset[targetDepth - 1];
						}
					}
				}
			}
			// 不支持交换机
			else
			{
				initHeaders();
			}

			// 协议版本号 + 包标识符 + 附属设备当前级联深度 + 分控当前级联深度
			byte[] infoField = Tools.StringToHexByte("81C50100000000");		// 51 ~ 57字节
			
			// 附属设备当前级联深度 = 0, 分控当前级联深度 = 0

			/************************* 目标地址 58~61字节 **************************/

			// 地址类型
			byte addrType;

			if (overallFlag)
			{
				addrType = 0x1;		// "全局操作"分控, bit0=1, bit1无用, bit7~bit2为0 
			}
			else
			{
				addrType = 0x0;		// "定点操作"分控, bit0=0, bit1无用, bit7~bit2为0 
			}

			// 校验目标分控深度
			if (target.Equals(InnerCommandTarget.SubCtrl))
			{
				if (targetDepth < 0 || targetDepth > 255)
				{
					throw new Exception("Wrong targetSubCtrlDepth value: " + targetDepth);
				}
			}
			else if (target.Equals(InnerCommandTarget.Equipment))
			{
				if (targetDepth < 0 || targetDepth > 63)
				{
					throw new Exception("Wrong targetEquipmentDepth value: " + targetDepth);
				}
			}

			/*
			// 地址字节1
			byte addr1 = (byte)(0xff & subControlDepth);	// 分控的目标级联深度

			// 地址字节2
			byte addr2 = 0x0;	// 暂为0

			// 地址字节3
			byte addr3 = 0x0;	// 暂为0
			*/

			byte addr1 = 0x0;	// 地址字节1 - 目标分控级联深度
			if (target.Equals(InnerCommandTarget.SubCtrl))
				addr1 = (byte)(0xff & targetDepth);
			else
				addr1 = 0x0;	// 为 0, 表示不操作任何分控

			byte addr2 = 0x0;	// 地址字节2 - 分控定点分线器号 - 暂为 0

			byte addr3 = 0x0;	// 地址字节3 - 目标附属设备级联深度
			if (target.Equals(InnerCommandTarget.Equipment))
				addr3 = (byte)(0xff & targetDepth);
			else
				addr3 = 0x0;	// 为 0, 表示不操作任何附属设备

			byte[] targetAddr = new byte[4];
			targetAddr[0] = addrType;
			targetAddr[1] = addr1;
			targetAddr[2] = addr2;
			targetAddr[3] = addr3;

			/**************************** END 目标地址 ******************************/

			byte[] effectDataLenth = Tools.int2Byte2(264);	// 有效数据长度 2+1+1+1+1+1+1+256=264

			/****************************** 命令数据 64 ********************************/

			byte[] pkgId = Tools.int2Byte2(packageId);

			// 命令类型
			byte commandCode = 0x04;		// 写 Memory：0x04

			// 保留字节
			byte resveredInCmdData = 0x00;

			// 命令地址 - 4字节 - loadData 数据要写入的命令地址
			byte[] addrInCmdData = Tools.int2Byte4(addr2Write);

			// 命令数据 - 256字节
			byte[] dataInCmdData = new byte[256];
			for (int k = 0; k < 256; k++)
			{
				dataInCmdData[k] = 0x0;
			}
			for (int k = 0; k < loadData.Length; k++)
			{
				dataInCmdData[k] = loadData[k];
			}

			/*********************** END命令数据 ************************/

			byte[] ipHeader_fix;
			byte[] udpHeader_fix;
			if (useUDP == true)
			{
				// Fix：修正 IP 帧头 - 设置有效数据长度 = 305 = 0x0131
				ipHeader_fix = Tools.StringToHexByte("450001315F69000001110000AC100150E0010101");

				// Fix：修正 UDP 帧头 - 设置有效数据长度 = 285 = 0x011D
				udpHeader_fix = Tools.StringToHexByte("55A955AA011D8EA2");
			}
			else
			{
				// 借用 macHeader 变量, 实际为广播目的地址
				macHeader = Tools.StringToHexByte("FFFFFFFFFFFF");

				// 借用 ipHeader 变量, 实际为广播源地址
				ipHeader = Tools.StringToHexByte("000000000000");

				// 借用 ipHeader 变量, 实际为目的端口 55AA
				udpHeader = Tools.StringToHexByte("55AA");

				ipHeader_fix = ipHeader;
				udpHeader_fix = udpHeader;
			}

			// 包头长度： MAC帧头 + IP帧头 + UDP帧头
			int totalHeaderLength = 0;
			if (useSwitch == true && macHeader4Switch != null)
			{
				totalHeaderLength = macHeader4Switch.Length + ipHeader_fix.Length + udpHeader_fix.Length;
			}
			else
			{
				totalHeaderLength = macHeader.Length + ipHeader_fix.Length + udpHeader_fix.Length;
			}

			// 组装完整的通信命令包
			int totalLength = 0;
			if (useWinPcap)
			{
				totalLength = totalHeaderLength + infoField.Length + targetAddr.Length + effectDataLenth.Length	+ pkgId.Length + 1 + 1 + addrInCmdData.Length + dataInCmdData.Length;
			}
			else
			{
				totalLength = infoField.Length + targetAddr.Length + effectDataLenth.Length + pkgId.Length + 1 + 1 + addrInCmdData.Length + dataInCmdData.Length;
			}

			byte[] allFrameBytes = new byte[totalLength];

			int index = 0;
			if (useWinPcap)
			{
				if (useSwitch == true && macHeader4Switch != null)
				{
					Tools.addByte(ref allFrameBytes, macHeader4Switch, ref index);
				}
				else
				{
					Tools.addByte(ref allFrameBytes, macHeader, ref index);
				}
				Tools.addByte(ref allFrameBytes, ipHeader_fix, ref index);
				Tools.addByte(ref allFrameBytes, udpHeader_fix, ref index);
			}
			Tools.addByte(ref allFrameBytes, infoField, ref index);
			Tools.addByte(ref allFrameBytes, targetAddr, ref index);
			Tools.addByte(ref allFrameBytes, effectDataLenth, ref index);
			Tools.addByte(ref allFrameBytes, pkgId, ref index);
			Tools.addByte(ref allFrameBytes, commandCode, ref index);
			Tools.addByte(ref allFrameBytes, resveredInCmdData, ref index);
			Tools.addByte(ref allFrameBytes, addrInCmdData, ref index);
			Tools.addByte(ref allFrameBytes, dataInCmdData, ref index);

			// winpcap发包：设置【通信命令包】校验和 CAF0
			if (useWinPcap)
			{
				if (useUDP)
				{
					allFrameBytes[0x18] = 0xCA;
					allFrameBytes[0x19] = 0xF0;
				}
			}

			return allFrameBytes;
		}

        public byte[] generateARPPacket(string targetIP, string targetMAC, string sourceIP, string sourceMAC, int requestType)
        {
            byte[] ARPPacket = new byte[42];
            byte[] targetMacByte = Tools.StringToHexByte(targetMAC);
            byte[] sourceMacByte = Tools.StringToHexByte(sourceMAC);
            byte[] targetIPByte = Tools.IP2Byte(targetIP);
            byte[] sourceIPByte = Tools.IP2Byte(sourceIP);
            // Ethernet Header
            // Destiantion MAC - 6byte:0
            for (int i = 0; i < 6; i++)
            {
                ARPPacket[i] = targetMacByte[i];
            }

            // Source MAC - 6byte:6
            for (int i = 0; i < 6; i++)
            {
                ARPPacket[i + 6] = sourceMacByte[i];
            }

            // protocol - 2byte:12
            ARPPacket[12] = 0x08;
            ARPPacket[13] = 0x06; //0x0608 - ARP 低位先传
            // hardware type - 2byte:14
            ARPPacket[14] = 0x00;
            ARPPacket[15] = 0x01;
            // protocol type - 2byte:16
            ARPPacket[16] = 0x08;
            ARPPacket[17] = 0x00;
            // hardware size - 1byte:18
            ARPPacket[18] = 0x06;
            // protocol size - 1byte:19
            ARPPacket[19] = 0x04;
            // OpCode - 2byte:20
            ARPPacket[20] = 0x00;
            if (requestType == 1)
            {
                ARPPacket[21] = 0x01;
            }
            else
            {
                ARPPacket[21] = 0x02;
            }
            // Source MAC - 6byte:22
            for (int i = 0; i < 6; i++)
            {
                ARPPacket[22 + i] = sourceMacByte[i];
            }
            // Source IP - 4byte:28
            for (int i = 0; i < 4; i++)
            {
                ARPPacket[28 + i] = sourceIPByte[i];
            }
            // Target MAC - 6byte:32
            if (targetMacByte[0] == 0xff)
            {
                for (int i = 0; i < 6; i++)
                {
                    ARPPacket[32 + i] = 0x00;
                }
            }
            else
            {
                for (int i = 0; i < 6; i++)
                {
                    ARPPacket[32 + i] = targetMacByte[i];
                }
            }
            // target IP - 4byte:38
            for (int i = 0; i < 4; i++)
            {
                ARPPacket[38 + i] = targetIPByte[i];
            }

            return ARPPacket;
        }

        public byte[] gengrateArtNetPacket(string targetIP, string targetMAC, string sourceIP, string sourceMAC, int messagelen, byte[] message)
        {
            byte[] ArtPacket = new byte[messagelen + 42];

            UInt16 totalLen = (UInt16)(messagelen + 28);
            UInt16 UDPLen = (UInt16)(messagelen + 8);

            byte[] targetMacByte = Tools.StringToHexByte(targetMAC);
            byte[] sourceMacByte = Tools.StringToHexByte(sourceMAC);
            byte[] targetIPByte = Tools.IP2Byte(targetIP);
            byte[] sourceIPByte = Tools.IP2Byte(sourceIP);

            // Ethernet Header
            // Destiantion MAC - 6byte:0
            for (int i = 0; i < 6; i++)
            {
                ArtPacket[i] = targetMacByte[i];
            }

            // Source MAC - 6byte:6
            for (int i = 0; i < 6; i++)
            {
                ArtPacket[i + 6] = sourceMacByte[i];
            }

            // protocol - 2byte:12
            ArtPacket[12] = 8;
            ArtPacket[13] = 0; //0x0008 - UDP 低位先传

            // IP Header
            // Version - 1byte:14
            ArtPacket[14] = 0x45; //IPv4

            // Differntiated services field - 1byte:15
            ArtPacket[15] = 0;

            // Total Length - 2byte:16
            ArtPacket[16] = (byte)((totalLen >> 8) & 0xff);
            ArtPacket[17] = (byte)(totalLen & 0xff);

            // ID - 2byte:18
            ArtPacket[18] = 0x00;
            ArtPacket[19] = 0x05;

            // falg - 1byte:20
            ArtPacket[20] = 0;

            // offset - 1byte:21
            ArtPacket[21] = 0;

            // Time to live - 1byte:22
            ArtPacket[22] = 64;

            // Protocol - 1byte:23
            ArtPacket[23] = 0x11;

            // Checksum - 2byte:24
            ArtPacket[24] = 0;
            ArtPacket[25] = 0; //Set to 0 for Calculate

            // SourceIP - 4byte:26
            for (int i = 0; i < 4; i++)
            {
                ArtPacket[26 + i] = sourceIPByte[i];
            }

            // DestinationIP - 4byte:30
            for (int i = 0; i < 4; i++)
            {
                ArtPacket[30 + i] = targetIPByte[i];
            }

            // UDP Header
            // sourcePort - 2byte:34
            ArtPacket[34] = (byte)((BaseCoreNet.ArtNetPort >> 8) & 0xff);
            ArtPacket[35] = (byte)(BaseCoreNet.ArtNetPort & 0xff);

            // targetPort - 2byte:36
            ArtPacket[36] = (byte)((BaseCoreNet.ArtNetPort >> 8) & 0xff); ;
            ArtPacket[37] = (byte)(BaseCoreNet.ArtNetPort & 0xff);

            // UDP Length - 2byte:38
            ArtPacket[38] = (byte)((UDPLen >> 8) & 0xff);
            ArtPacket[39] = (byte)(UDPLen & 0xff);

            // UDPCheckSUM - 2byte:40
            ArtPacket[40] = 0;
            ArtPacket[41] = 0;

            // UDP Body - (len)byte:42
            for (int i = 0; i < messagelen; i++)
            {
                ArtPacket[42 + i] = message[i];
            }

            // Calculate & Set CheckSum Number
            UInt16 IPChecksum = CalIPChecksum(ArtPacket);
            UInt16 UDPChecksum = CalUDPChecksum(ArtPacket, messagelen);

            ArtPacket[24] = (byte)((IPChecksum) >> 8 & 0xff);
            ArtPacket[25] = (byte)(IPChecksum & 0xff);

            ArtPacket[40] = (byte)(UDPChecksum & 0xff);
            ArtPacket[41] = (byte)((UDPChecksum >> 8) & 0xff);
            return ArtPacket;
        }

        private UInt16 CalIPChecksum(byte[] packet)
        {
            UInt16 checksum = 0;
            for (int i = 14; i < 34; i += 2)
            {
                UInt16 temp = Tools.BytesTo16(packet[i], packet[i + 1]);
                UInt16 difference = (UInt16)((UInt16.MaxValue - checksum) & 0xffff);
                checksum += temp;
                if (temp > difference) checksum++;
            }

            checksum = (UInt16)((~checksum) & 0xffff);
            return checksum;
        }

        private UInt16 CalUDPChecksum(byte[] packet, int messagelen)
        {
            UInt16 checksum = 0;
            UInt16 PseudoLength = (UInt16)(messagelen + 9 + 8);
            UInt16 Length = (UInt16)(messagelen + 8);
            PseudoLength += (UInt16)(PseudoLength % 2);

            byte[] PseudoHeader = new byte[PseudoLength];

            PseudoHeader[0] = 0x11;
            Tools.CopyByte(ref PseudoHeader, packet, 8, 1, 26);
            PseudoHeader[9] = (byte)((Length >> 8) & 0xff);
            PseudoHeader[10] = (byte)(Length & 0xff);
            PseudoHeader[11] = (byte)((Length >> 8) & 0xff);
            PseudoHeader[12] = (byte)(Length & 0xff);
            Tools.CopyByte(ref PseudoHeader, packet, 4, 13, 34);
            Tools.CopyByte(ref PseudoHeader, packet, messagelen, 17, 42);

            for (int i = 0; i < PseudoLength; i += 2)
            {
                UInt16 Tmp = Tools.BytesTo16(PseudoHeader[i], PseudoHeader[i + 1]);
                UInt16 Difference = (UInt16)((UInt16.MaxValue - checksum) & 0xffff);
                checksum += Tmp;
                if (Tmp > Difference) { checksum += 1; }
            }
            checksum = (UInt16)((~checksum) & 0xffff);

            return checksum;
        }

        public byte[] addIdleUDPHeader(byte[] packet) {
            var ret = new byte[packet.Length + idleHeader_UDP.Length];
            Array.Copy(idleHeader_UDP, ret, idleHeader_UDP.Length);
            Array.Copy(packet, 0, ret, idleHeader_UDP.Length, packet.Length);
            return ret;
        }
	}
}
